package DataFile;

import java.nio.ByteBuffer;
import java.util.Formatter;

import ClassData.ExceptionHandler;
import ClassData.MethodInfo;

/**
 * 
 * @note changed by Dominik Ollesz
 */
public class Structure_MethodData extends Structure_Template {

	MethodInfo myMethodInfo;
	short functionNumber;
	
	private Structure_ExceptionHandlerTable exceptionHandlerTable;
	private int offset_exceptionsHandlerTable = 0;
	
	private Structure_ExceptionsTable exceptionsTable;
	private int offset_exceptionsTable = 0;
	
	public Structure_MethodData(MethodInfo myMethodInfo) {
		this.myMethodInfo = myMethodInfo;
	}

	protected int setBaseAddress(int newBaseAdress) {
		baseAdress=newBaseAdress;		
		return(newBaseAdress+getMemorySize());
	}
	
	protected int getMemorySize() {
		int size;
	
		size =ADRESS_WIDTH; // Pointer to exception handler table
		size+=SHORT_WIDTH;  // offset into exception handler table
		size+=SHORT_WIDTH;  // length (how many exception handlers)
		
		size+=ADRESS_WIDTH; // Pointer to exceptions table
		size+=SHORT_WIDTH;  // offset into exceptions table
		size+=SHORT_WIDTH;  // length (how many exceptions)
		
		size+=SHORT_WIDTH;  // AccesFlags  
		size+=SHORT_WIDTH;  // nameIndex
		size+=SHORT_WIDTH;  // descriptorIndex
		size+=SHORT_WIDTH;  // max_stack;
		size+=SHORT_WIDTH;	// max_locals;
				
		size+=SHORT_WIDTH;	// CodeLenght;
		size+=myMethodInfo.getCodeSize();	
		
		if (myMethodInfo.isNative()) {
			size+=2;
		}
		
		size+=myMethodInfo.getParameterCount()+1;
		
// ORIGINAL
//		if ((size %2 )> 0)
//				size++;
		
		// new
		while((size % 4) > 0) size++;
		
		return(size);	
	}

	public int getDescriptorIndex() {
		return(myMethodInfo.getDescriptorIndex());
	}

	public String getMethodName() {
		return(myMethodInfo.getMethodName());
	}

	protected String getMemoryMapAsString() {
		String returnString;
		
		Formatter fmt = new Formatter();
		
		returnString="";
		returnString+=getAdressAsHexString(baseAdress) + " : " + fmt.format("%-20s",myMethodInfo.getMethodName());
		
		fmt = new Formatter();
		returnString+=" : size - " + fmt.format("%4d",getMemorySize());
		//returnString+=" : Data offset - "+dataOffset;
		/*
		returnString+=" : descriptor index - "+myMethodInfo.getDescriptorIndex();
		returnString+=" : name index - "+myMethodInfo.getNameIndex();
		*/
		fmt = new Formatter();
		returnString+=" : code size - " + fmt.format("%4d",myMethodInfo.getCodeSize());
		
		
		returnString+=" : flags - ("+Integer.toHexString(myMethodInfo.getFlags());
		returnString+=") "+myMethodInfo.getFlagsAsString();
		
		fmt = new Formatter();
		returnString+=" : parameters - ("+Integer.toHexString(myMethodInfo.getParameterList().length);
		returnString+=") "+myMethodInfo.getParametersAsString();

		
		returnString+="\n";
		return(returnString);
	}

	/**
	 *  writes data into memory file
	 *  
	 *  @author Tavin
	 *  
	 *  @param fileData buffer for data 
	 *  @note changed by Dominik Ollesz
	 */
	public void writeData(ByteBuffer fileData) {
		
		byte [] code;
		byte [] parameters;
		
		fileData.position(baseAdress-DataFileCreator.BASE_MEMORY_ADRESS);
		
		if (exceptionHandlerTable == null) {                                            // NO EXCEPTION HANDLER TABLE:
			fileData.putInt((int)0);                                                    //   4 Bytes: Address = 0x00000000
			fileData.putInt((int)0);                                                    //   4 Bytes: offset = 0000, length = 0000
		} else {                                                                        // EXEPTION HANDLER TABLE:
			if (myMethodInfo.getExceptionHandlers() > 0) {
				fileData.putInt(exceptionHandlerTable.getBaseAddress());                //   4 Bytes: Address to exception handler table
				fileData.putShort((short)offset_exceptionsHandlerTable);                //   2 Bytes: offset
				fileData.putShort((short)(myMethodInfo.getExceptionHandler().length));  //   2 Bytes: length = exception handlers
			} else {
				fileData.putInt((int)0);                                                //   4 Bytes: Address = 0x00000000
				fileData.putInt((int)0);                                                //   4 Bytes: offset = 0000, length = 0000
			}
		}
		
		if (exceptionsTable == null) {                                                  // NO EXCEPTIONS TABLE
			fileData.putInt((int)0);                                                    //   4 Bytes: Address = 0x00000000
			fileData.putInt((int)0);                                                    //   4 Bytes: offset = 0000, length = 0000
		} else {		                                                                // EXCEPTIONS TABLE
			if (myMethodInfo.getExceptions() != null) {
				fileData.putInt(exceptionsTable.getBaseAddress());                      //   4 Bytes: Address to exceptions table
				fileData.putShort((short)offset_exceptionsTable);                       //   2 Bytes: offset
				fileData.putShort((short)myMethodInfo.getExceptions().length);          //   2 Bytes: length = exceptions
			} else {
				fileData.putInt((int)0);
				fileData.putInt((int)0);                                            //   2 Bytes: length = 0000
			}
		}
		
		fileData.putShort((short)myMethodInfo.getFlags());                 //  2 Bytes           : AccessFlags
		fileData.putShort((short)myMethodInfo.getNameIndex());             //  2 Bytes           : NameIndex
		fileData.putShort((short)myMethodInfo.getDescriptorIndex());       //  2 Bytes           : DescriptorIndex
		fileData.putShort((short)myMethodInfo.getMaxStack());              //  2 Bytes           : MaxStack
		fileData.putShort((short)myMethodInfo.getMaxLocals());             //  2 Bytes           : MaxLocals
				
		if (myMethodInfo.isNative()) {                                     //  NATIVE
			fileData.putShort(functionNumber);                             //  2 Bytes           : 
		} else {

			code=myMethodInfo.getCode();
			if (code !=null) {                                             //  CODE
				fileData.putShort((short)code.length);                     //  2 Bytes           : CodeSize
				fileData.put(code);                                        //  1 Byte * codesize : content of code
			} else {
				fileData.putShort((short)0);                               //  2 Bytes           : CodeSize
			}
		}
			
		parameters=myMethodInfo.getParameterList();                        //  PARAMETER
		fileData.put((byte)parameters.length);                             //  1 Byte            : parameter length
		if (parameters !=null)
			fileData.put(parameters);                                      //  1 Byte * parameter length : 
		else {
			System.out.println("no code for  :"+baseAdress);
		}
	}

	public boolean isPrivate() {
		return(myMethodInfo.isPrivate());
	}
	
	public boolean isNative() {
		return(myMethodInfo.isNative());
	}
	
	public boolean isStatic() {
		return(myMethodInfo.isStatic());
	}
	
	public String getParametersAsString() {
		return(myMethodInfo.getParametersAsString());
	}
	
	public void setFunctionNumber(short newfunctionNumber) {
		functionNumber=newfunctionNumber;
	}
	
	/**
	 * @author Dominik Ollesz
	 */
	public void setExceptionHandlerTable(Structure_ExceptionHandlerTable table) {
		ExceptionHandler exceptionHandlers[] = myMethodInfo.getExceptionHandler();
		if ((exceptionHandlers != null) && (exceptionHandlers.length > 0)) {
			this.exceptionHandlerTable    = table;
			offset_exceptionsHandlerTable = table.size();
			this.exceptionHandlerTable.addExceptionHandlers(myMethodInfo.getExceptionHandler());
		} else {
			exceptionHandlerTable = null;
		}
	}
	
	/**
	 * @author Dominik Ollesz
	 */
	public void setExceptionsTable(Structure_ExceptionsTable table) {
		this.exceptionsTable   = table;
		offset_exceptionsTable = table.size();
		this.exceptionsTable.addExceptions(myMethodInfo.getExceptions());
	}
	
}
